package client;

public class Run extends Thread {
	
	private long gameStartTime;
	private static final int NO_DELAYS_PER_YIELD = 16;
	/*
	 * Number of frames with a delay of 0 ms before the animation thread yields
	 * to other running threads.
	 */
	private static int MAX_FRAME_SKIPS = 5; // was 2;

	private long framesSkipped = 0L;

	public static final int DEFAULT_FPS = 45; //15
	//private static final int DEFAULT_UPS = 35;
	private Main m;
	private boolean run = false;
	private int fps = DEFAULT_FPS;
	//private int ups = DEFAULT_UPS; //Updates per second
	private long framePeriod = (((long) 1000.0 / fps) * 1000000L); //in nano
	//private long updatePeriod = (((long) 1000.0 / ups) * 1000000L); //in nano
	
	public Run(Main m) {
		this.m = m;
	}

	public void setRunning(boolean run) {
		this.run = run;
	}

	@Override
	public void run() {
		/* The frames of the animation are drawn inside the while loop. */
		long beforeTime, afterTime, timeDiff, sleepTime = 0L;
		long overSleepTime = 0L;
		//long fPeriod = framePeriod;
		//long uPeriod = updatePeriod;
		int noDelays = 0;
		long excess = 0L;
		//boolean update[] = {true, true};
		gameStartTime = System.nanoTime();
		beforeTime = gameStartTime;
		run = true;
		while (run) {
			m.repaint();
			m.gameUpdate();
			/*if(update[0]) {
				m.gameUpdate();
				uPeriod = updatePeriod;
				update[0] = false;
			}
			if(update[1]) {
				m.repaint();
				fPeriod = framePeriod;
				update[1] = false;
			}*/
			afterTime = System.nanoTime();
			timeDiff = afterTime - beforeTime;
			/*if(fPeriod < uPeriod) {
				sleepTime = (fPeriod - timeDiff) - overSleepTime;
				fPeriod = 0L;
				uPeriod -= sleepTime;
				update[1] = true;
			} else {
				sleepTime = (uPeriod - timeDiff) - overSleepTime;
				uPeriod = 0L;
				fPeriod -= sleepTime;
				update[0] = true;
			}*/
			sleepTime = (framePeriod - timeDiff) - overSleepTime;
			if (sleepTime > 0) { // some time left in this cycle
				try {
					Thread.sleep(sleepTime / 1000000L); // nano -> ms
				} catch (InterruptedException ex) {
				}
				overSleepTime = (System.nanoTime() - afterTime) - sleepTime;
			} else { // sleepTime <= 0; the frame took longer than the period
				excess -= sleepTime; // store excess time value
				overSleepTime = 0L;
				if (++noDelays >= NO_DELAYS_PER_YIELD) {
					Thread.yield(); // give another thread a chance to run
					noDelays = 0;
				}
			}
			beforeTime = System.nanoTime();
			/*
			 * If frame animation is taking too long, update the game state
			 * without rendering it, to get the updates/sec nearer to the
			 * required FPS.
			 */
			int skips = 0;
			while ((excess > framePeriod) && (skips < MAX_FRAME_SKIPS)) {
				excess -= framePeriod;
				m.gameUpdate(); // update state but don't render
				skips++;
			}
			framesSkipped += skips;
		}
		Thread.yield();
	}
}